package com.vietnam.power.dao.impl;

import java.util.ArrayList;
import java.util.List;

import org.apache.commons.collections.CollectionUtils;
import org.hibernate.Criteria;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.LogicalExpression;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.vietnam.power.dao.ProductDao;
import com.vietnam.power.domain.ProductGroupSearchCriteria;
import com.vietnam.power.domain.ProductSearchCriteria;
import com.vietnam.power.persitence.Product;
import com.vietnam.power.persitence.ProductGroup;
import com.vietnam.power.persitence.SubProductGroup;

@Repository
@Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED)
public class ProductDaoImpl extends GenericDaoImpl implements ProductDao {

	@SuppressWarnings("unchecked")
	public List<ProductGroup> getProductGroupAsClientMenu() {
		Criteria crt = getSessionFactory().getCurrentSession().createCriteria(ProductGroup.class);

		crt.add(Restrictions.eq("status", Boolean.TRUE));
		return crt.list();
	}

	@SuppressWarnings("unchecked")
	public List<Product> getAllProductList(ProductSearchCriteria psc, int page, int max) {
		Criteria crt = getSessionFactory().getCurrentSession().createCriteria(Product.class);
		if (psc != null && psc.getProductGroupId() != null) {
			crt.createAlias("productGroup", "pG");
			crt.add(Restrictions.in("pG.id", getSubProductGroupsByParentId(psc.getProductGroupId())));
		}
		if (psc != null && psc.getCurrentProductId() != null) {
			crt.add(Restrictions.ne("id", psc.getCurrentProductId()));
		}

		List<Criterion> lstCrt = new ArrayList<Criterion>();
		if (psc != null && psc.getKeyword() != null) {
			lstCrt.add(Restrictions.ilike("keyword", psc.getKeyword(), MatchMode.ANYWHERE));
		}
		if (psc != null && psc.getName() != null) {
			lstCrt.add(Restrictions.ilike("name", psc.getName(), MatchMode.ANYWHERE));
		}

		if (CollectionUtils.isNotEmpty(lstCrt)) {
			if (lstCrt.size() == 1) {
				crt.add(lstCrt.get(0));
			} else if (lstCrt.size() == 2) {
				LogicalExpression orExp = Restrictions.or(lstCrt.get(0), lstCrt.get(1));
				crt.add(orExp);
			}
		}

		crt.add(Restrictions.eq("status", Boolean.TRUE));
		crt.setFirstResult((page - 1) * max);
		crt.setMaxResults(max);

		return crt.list();
	}

	public int totalProduct(ProductSearchCriteria psc) {
		Criteria crt = getSessionFactory().getCurrentSession().createCriteria(Product.class);
		if (psc != null && psc.getProductGroupId() != null) {
			crt.createAlias("productGroup", "pG");
			crt.add(Restrictions.in("pG.id", getSubProductGroupsByParentId(psc.getProductGroupId())));
		}
		if (psc != null && psc.getCurrentProductId() != null) {
			crt.add(Restrictions.ne("id", psc.getCurrentProductId()));
		}

		List<Criterion> lstCrt = new ArrayList<Criterion>();
		if (psc != null && psc.getKeyword() != null) {
			lstCrt.add(Restrictions.ilike("keyword", psc.getKeyword(), MatchMode.ANYWHERE));
		}
		if (psc != null && psc.getName() != null) {
			lstCrt.add(Restrictions.ilike("name", psc.getName(), MatchMode.ANYWHERE));
		}

		if (CollectionUtils.isNotEmpty(lstCrt)) {
			if (lstCrt.size() == 1) {
				crt.add(lstCrt.get(0));
			} else if (lstCrt.size() == 2) {
				LogicalExpression orExp = Restrictions.or(lstCrt.get(0), lstCrt.get(1));
				crt.add(orExp);
			}
		}

		crt.add(Restrictions.eq("status", Boolean.TRUE));
		crt.setProjection(Projections.rowCount());

		return ((Long) crt.uniqueResult()).intValue();
	}

	private List<Integer> getSubProductGroupsByParentId(int productGroupId) {
		List<Integer> pGIdList = new ArrayList<Integer>();
		pGIdList.add(productGroupId);
		ProductGroup pg = findById(ProductGroup.class, productGroupId);

		for (SubProductGroup child : pg.getSubProductGroups2()) {
			pGIdList.add(child.getProductGroup1().getId());
		}

		return pGIdList;
	}

	public Product getProductById(int pId) {
		return findById(Product.class, pId);
	}

	public void createProductGroup(ProductGroup pg) {
		save(pg);
	}

	public ProductGroup getProductGroupById(int id) {
		return findById(ProductGroup.class, id);
	}

	public void updateProductGroup(ProductGroup pg) {
		merge(pg);
	}

	public void deleteProductGroup(ProductGroup pg) {
		delete(pg);
	}

	public void createProduct(Product p) {
		save(p);
	}

	public void updateProduct(Product p) {
		merge(p);
	}

	public void deleteProduct(Product p) {
		delete(p);
	}

	@SuppressWarnings("unchecked")
	public List<ProductGroup> searchProductGroup(ProductGroupSearchCriteria s) {
		Criteria crt = getSessionFactory().getCurrentSession().createCriteria(ProductGroup.class);

		if (s.getStatus() != null) {
			crt.add(Restrictions.eq("status", s.getStatus()));
		}

		if (s.getName() != null) {
			crt.add(Restrictions.ilike("name", s.getName(), MatchMode.ANYWHERE));
		}

		if (s.getKeyword() != null) {
			crt.add(Restrictions.ilike("keyword", s.getKeyword(), MatchMode.ANYWHERE));
		}

		return crt.list();
	}

	public List<Product> searchProduct(ProductSearchCriteria s) {
		Criteria crt = getSessionFactory().getCurrentSession().createCriteria(Product.class);

		if (s.getStatus() != null) {
			crt.add(Restrictions.eq("status", s.getStatus()));
		}

		if (s.getName() != null) {
			crt.add(Restrictions.ilike("name", s.getName(), MatchMode.ANYWHERE));
		}

		if (s.getKeyword() != null) {
			crt.add(Restrictions.ilike("keyword", s.getKeyword(), MatchMode.ANYWHERE));
		}

		return crt.list();
	}
}
